﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Collections.ObjectModel;

namespace nuc2hex
{
    public partial class Form1 : Form
    {

        [DllImport("user32.dll")]
        static extern bool GetCursorPos(ref Point lpPoint);

        [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
        public static extern int BitBlt(IntPtr hDC, int x, int y, int nWidth, int nHeight, IntPtr hSrcDC, int xSrc, int ySrc, int dwRop);

        string transTable = "tcag";

        Color[] colors;
        Brush[] brushes;
        Pen[] pens;
        public double[] BrushMask = new double[] { 1, 1, 1, 1 }; // ARGB
        public int schale = 2;

        int[,] SumMartrix = new int[256, 256];
        int[] median = new int[257];
        int maxMatrixVal = 0;
        int maxX = 0, maxY = 0;

        private string Hex2nucl(byte num)
        {
            char[] tr = transTable.ToCharArray();
            char ch0 = tr[(num & 0xC0) >> 6];
            char ch1 = tr[(num & 0x30) >> 4];
            char ch2 = tr[(num & 0x0C) >> 2];
            char ch3 = tr[(num & 0x03)];
            return string.Format("{0}{1}{2}{3}", ch0, ch1, ch2, ch3);
        }

        public CheckBox _chckDraw { get { return chckDraw; } }

        public Form1()
        {
            InitializeComponent();

            fsCmbBox.SelectedIndex = 0;

            string[] args = Environment.GetCommandLineArgs();
            if (args.Length > 1)
            {
                txtSource.Text = args[1];
            }
            txtResultHex.Text = txtSource.Text + "." + transTable + ".n-t.hex";
            txtSM.Text = txtResultHex.Text + ".sm";

            colors = new Color[]
            { Color.FromArgb(0x8000000), 
              Color.FromArgb(0xF0000FF), 
              Color.FromArgb(0xF00FF00), 
              Color.FromArgb(0xFFF0000) };

            brushes = new Brush[]
            { new SolidBrush(colors[0]), 
              new SolidBrush(colors[1]),  
              new SolidBrush(colors[2]),  
              new SolidBrush(colors[3])  
            };

            pens = new Pen[]
            { new Pen(brushes[0]),
              new Pen(brushes[1]),
              new Pen(brushes[2]),
              new Pen(brushes[3])
            };

        }

        private void cmdFileOpen_Click(object sender, EventArgs e)
        {
            iLine = 0;

            ShowOpenDialog("FASTA Files (*.fa, *.fna, *.fasta)|*.fa;*.fna;*.fasta", txtSource);

            //DialogResult res = openFileDialog1.ShowDialog();
            //if (res == DialogResult.OK)
            //{
            //    txtSource.Text = openFileDialog1.FileName;
            //    txtResult.Text = txtSource.Text + "." + transTable + ".n-t.hex";
            //    txtSM.Text = txtResult.Text + ".sm";
            //}
        }

        private void cmdFileSave_Click(object sender, EventArgs e)
        {
            saveFileDialog1.AddExtension = true;
            saveFileDialog1.DefaultExt = ".hex";
            saveFileDialog1.InitialDirectory = Path.GetDirectoryName(txtResultHex.Text);
            DialogResult res = saveFileDialog1.ShowDialog();
            if (res == DialogResult.OK)
            {
                txtResultHex.Text = saveFileDialog1.FileName;
            }
        }

        private void cmdTransform_Click(object sender, EventArgs e)
        {
            using (FileStream fs = new FileStream(txtSource.Text, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                using (TextReader read = new StreamReader(fs))
                {
                    string resFile = txtResultHex.Text;
                    using (FileStream write = new FileStream(resFile, FileMode.Create))
                    {
                        string line = NextLine(read);
                        string tail = "";

                        SumMatrixClear();

                        // !!! shift-test !!!
                        //line = line.Substring(3);
                        bool isFS = true;
                        while (!string.IsNullOrEmpty(line))
                        {
                            if (line.StartsWith(">"))
                            {
                                line = NextLine(read);
                                continue;
                            }

                            if (isFS)
                            {
                                // frame shift
                                line = line.Substring(int.Parse(fsCmbBox.Text));
                                isFS = false;
                            }

                            line = line.Replace("N", "t"); // N=aNy, ->0
                            string fourPack;
                            char[] fourChar;
                            byte[] twoBytes = new byte[2]; int indByte = 0;
                            for (int i = 0; i < (line.Length / 4 + 1); i++)
                            {
                                tail = line.Substring(i * 4);
                                if (tail.Length >= 4)
                                {
                                    fourPack = tail.Substring(0, 4).ToLower();
                                    fourChar = fourPack.ToCharArray();
                                    int iByte =
                                        transTable.IndexOf(fourChar[3]) +
                                        (transTable.IndexOf(fourChar[2]) << 2) +
                                        (transTable.IndexOf(fourChar[1]) << 4) +
                                        (transTable.IndexOf(fourChar[0]) << 6);
                                    if (iByte >= 0 && iByte < 256)
                                    {
                                        byte bByte = (byte)iByte;
                                        char oneByte = (char)bByte;
                                        WriteNext(write, oneByte);

                                        // create SumMatrix on a fly
                                        if (indByte == 0)
                                        {
                                            twoBytes[0] = bByte;
                                            indByte++;
                                        }
                                        else
                                        {
                                            twoBytes[1] = bByte;
                                            indByte = 0;
                                            SumMartrix[twoBytes[0], twoBytes[1]]++;
                                        }
                                    }
                                }
                            }

                            string nextStr = NextLine(read);
                            if (string.IsNullOrEmpty(nextStr))
                            { // end of file
                                foreach (char ch in tail.ToCharArray())
                                {
                                    WriteNext(write, ch);

                                    // create SumMatrix on a fly
                                    if (indByte == 0)
                                    {
                                        twoBytes[0] = (byte)ch;
                                        indByte++;
                                    }
                                    else
                                    {
                                        twoBytes[1] = (byte)ch;
                                        indByte = 0;
                                        SumMartrix[twoBytes[0], twoBytes[1]]++;
                                    }

                                }
                                line = null;
                            }
                            else
                            {
                                line = tail + nextStr;
                            }
                        }

                        WriteNext(write, '.', true);
                        write.Close();
                        read.Close();

                        // write SumMatrix
                        using (FileStream writeSM = new FileStream(txtSM.Text, FileMode.Create))
                        using (TextWriter textSM = new StreamWriter(writeSM))
                        {
                            StringBuilder sb = new StringBuilder();
                            for (int y = 0; y <= SumMartrix.GetUpperBound(1); y++)
                            {
                                for (int x = 0; x <= SumMartrix.GetUpperBound(0); x++)
                                {
                                    sb.AppendFormat("{0}\t", SumMartrix[x, y]);
                                }
                                string aLine = sb.ToString();
                                aLine = aLine.TrimEnd('\t');
                                textSM.WriteLine(aLine);
                                sb.Clear();
                            }
                            textSM.Close();
                        }
                    }
                }
                lblLine.Text = iLine.ToString();
                fs.Close();

                panelSeq.Refresh();
                SaveSmImage(panelSeq, txtSM.Text + ".png");
            }
        }

        /// <summary>
        /// Transforms HEX to 4/3 
        /// groups by 3 prepended by tag (0x0 for now)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmdTo4_3_Click(object sender, EventArgs e)
        {
            string fileHex = txtResultHex.Text,
                file4_3 = fileHex + ".4_3";

        }

        List<byte> outArr = new List<byte>();
        private void WriteNext(FileStream write, char oneByte, bool final = false)
        {
            if (!final) { outArr.Add((byte)oneByte); }
            if (outArr.Count >= 8 || final)
            {
                write.Write(outArr.ToArray(), 0, outArr.Count);
                outArr.Clear();
            }
        }

        int iLine = 0;
        private string NextLine(TextReader read)
        {
            string line = read.ReadLine();
            iLine++;
            if (iLine % 1000 == 0)
            {
                lblLine.Text = iLine.ToString();
                lblLine.Refresh();
                //Thread.Sleep(0);
            }
            return line;
        }

        private void cmdDraw_Click(object sender, EventArgs e)
        {
            //panel1.Refresh();
            DrawFigure();
        }

        private void SumMatrixClear()
        {
            for (int x = 0; x <= SumMartrix.GetUpperBound(0); x++)
            {
                for (int y = 0; y <= SumMartrix.GetUpperBound(1); y++)
                {
                    SumMartrix[x, y] = 0;
                }
            }
        }

        private int[] SumMatrixSerialize()
        {
            int[] serializedSumMatrix = new int[256 * 256];
            for (int i = 0; i < 256; i++)
                for (int j = 0; j < 256; j++)
                {
                    serializedSumMatrix[i + j * 256] = SumMartrix[i, j];
                }

            return serializedSumMatrix;
        }

        private void SumMatrixCalc()
        {
            SumMatrixClear();
            using (FileStream fs = new FileStream(txtResultHex.Text, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                byte[] buf = new byte[bufSize];
                int bytesRead = 0;
                SumMartrix[0, 0] = 0; // stores max value
                while ((bytesRead = fs.Read(buf, 0, bufSize)) > 0)
                {
                    for (int i = 0; i < buf.Count() / 2; i++)
                    {
                        int x = buf[i * 2];
                        int y = buf[i * 2 + 1];
                        if (!(x == 0 && y == 0))
                        {
                            SumMartrix[x, y]++;
                            if (maxMatrixVal < SumMartrix[x, y])
                            {
                                maxMatrixVal = SumMartrix[x, y];
                                maxX = x; maxY = y;
                            }
                        }
                    }
                    SumMartrix[0, 0] = maxMatrixVal;
                }
                fs.Close();
            }
            int[] serializedSumMatrix = SumMatrixSerialize();
            var sorted = serializedSumMatrix.OrderBy(k => k).ToArray();
            for (int i = 0; i < 256; i++)
            {
                median[i] = sorted[i * 256];
            }
            median[256] = int.MaxValue;
        }

        int pos = 0;
        int bufSize = 4096 * 16; // 1/4 million of original nucs 
        public void DrawFigure()
        {
            Graphics g = panel1.CreateGraphics();
            //Graphics g2 = panelSeq.CreateGraphics();

            //g.Clear(Color.White);
            GraphicsPath path = new GraphicsPath();

            // 64K = 4096 * 16 = 0x1000 x 16 = 0x10000
            List<Point> figure = new List<Point>(bufSize);
            List<Rectangle> fig = new List<Rectangle>(bufSize);

            List<Point> figure2 = new List<Point>(bufSize);
            List<Rectangle> fig2 = new List<Rectangle>(bufSize);

            try
            {
                using (FileStream fs = new FileStream(txtResultHex.Text, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                {
                    fs.Position = pos;
                    //for (int k = 0; k < 1; k++)
                    //{
                    byte[] buf = new byte[bufSize];
                    int count = fs.Read(buf, 0, bufSize);
                    if (count > 0)
                    {
                        pos += bufSize;
                        
                        //lblLine.Text = (pos / 1024).ToString() + "K";
                        // to make it thread-safe
                        string newText = (pos / 1024).ToString() + "K"; // running on worker thread
                        this.Invoke((MethodInvoker)delegate
                        {
                            lblLine.Text = newText; // runs on UI thread
                        });

                        figure.Clear();
                        fig.Clear();

                        for (int i = 0; i < buf.Count() / 2; i++)
                        {
                            figure.Add(new Point(2 * buf[i * 2], 2 * buf[i * 2 + 1]));
                            fig.Add(new Rectangle(figure[i], new Size(2, 2)));
                        }
                        //path.AddLines(figure.ToArray());
                        //g.DrawPath(new Pen(color), path);

                        //g.FillRectangles(new SolidBrush(Color.Blue), fig.ToArray());
                        //g.FillRectangles(new SolidBrush(Color.FromArgb(0xf000000)), fig.ToArray());
                        //Brush brush = GetSmBrush(0xFF);
                        g.FillRectangles(brushes[0], fig.ToArray());

                        //bool showSeq = false;
                        //if (showSeq)
                        //{
                        //    figure2.Clear();
                        //    fig2.Clear();
                        //    if ((pos - bufSize) < (bufSize * 4))
                        //    {
                        //        int j = 0;
                        //        for (j = 0; j < buf.Count(); j = j + 2)
                        //        {
                        //            Point pp = new Point(buf[j], buf[j + 1]);
                        //            if (
                        //                (pp.X < 0x80 && pp.X > 0x70) && (pp.Y < 0x80 && pp.Y > 0x70)
                        //                )
                        //            {
                        //                figure2.Add(new Point((j + (pos - bufSize)) % 512, (j + (pos - bufSize)) / 512));
                        //                fig2.Add(new Rectangle(figure2[figure2.Count - 1], new Size(4, 2)));
                        //            }
                        //            else
                        //            {
                        //            }
                        //        }
                        //        //g2.FillRectangles(brushes[1], fig2.ToArray());
                        //        g2.FillRectangles(new SolidBrush(Color.Blue), fig2.ToArray());
                        //    }
                        //}
                        //}
                    }
                    fs.Close();
                }

            }
            catch (Exception ex)
            {
                toolStripStatusLabel1.Text = ex.Message;
            }
        }

        Brush brush0 = new SolidBrush(Color.FromArgb(0xF000000));
        public void DrawFigure16()
        {
            Graphics g = panel1.CreateGraphics();
            GraphicsPath path = new GraphicsPath();

            // 64K = 4096 * 16 = 0x1000 x 16 = 0x10000
            List<Point> figure = new List<Point>(bufSize);
            List<Rectangle> fig = new List<Rectangle>(bufSize);

            try
            {
                using (FileStream fs = new FileStream(txtResultHex.Text, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                {
                    fs.Position = pos;
                    //for (int k = 0; k < 1; k++)
                    //{
                    byte[] buf = new byte[bufSize];
                    int count = fs.Read(buf, 0, bufSize);
                    if (count > 0)
                    {
                        pos += bufSize;

                        // to make it thread-safe
                        string newText = (pos / 1024).ToString() + "K"; // running on worker thread
                        this.Invoke((MethodInvoker)delegate
                        {
                            lblLine.Text = newText; // runs on UI thread
                        });

                        figure.Clear();
                        fig.Clear();

                        for (int i = 0; i < buf.Count(); i++)
                        {
                            int x = buf[i]>>4,
                                y = buf[i] & 0x0F;
                            figure.Add(new Point(32 * x, 32 * y));
                            fig.Add(new Rectangle(figure[i], new Size(32, 32)));
                        }
                        g.FillRectangles(brush0, fig.ToArray());
                    }
                    fs.Close();
                }

            }
            catch (Exception ex)
            {
                toolStripStatusLabel1.Text = ex.Message;
            }
        }

        private void panel1_Paint(object sender, PaintEventArgs e)
        {
            if (pos > 0)
            {
                DrawFigure();
            }
        }

        private void cmdOpenRes_Click(object sender, EventArgs e)
        {
            ShowOpenDialog("Binary Files (*.hex)|*.hex", txtResultHex);
        }

        private void cmdClear_Click(object sender, EventArgs e)
        {
            ClearPanel();
        }

        private void ClearPanel()
        {
            pos = 0;
            panel1.CreateGraphics().Clear(DefaultBackColor);
            panelSeq.CreateGraphics().Clear(DefaultBackColor);
            chckRuler.Checked = false;
        }

        Bitmap screenPixel = new Bitmap(1, 1, PixelFormat.Format32bppArgb);
        public Color GetColorAt(Point location)
        {
            using (Graphics gdest = Graphics.FromImage(screenPixel))
            {
                using (Graphics gsrc = Graphics.FromHwnd(IntPtr.Zero))
                {
                    IntPtr hSrcDC = gsrc.GetHdc();
                    IntPtr hDC = gdest.GetHdc();
                    int retval = BitBlt(hDC, 0, 0, 1, 1, hSrcDC, location.X, location.Y, (int)CopyPixelOperation.SourceCopy);
                    gdest.ReleaseHdc();
                    gsrc.ReleaseHdc();
                }
            }

            return screenPixel.GetPixel(0, 0);
        }

        private void panel1_MouseMove(object sender, MouseEventArgs e)
        {
            ShowNucInfo(e);
        }

        private void ShowNucInfo(MouseEventArgs e)
        {
            int x = (int)(e.X / schale);
            int y = (int)(e.Y / schale);
            lblInfo.Text = string.Format("{0:X2}{1:X2}", x, y);

            Point cursor = new Point();
            GetCursorPos(ref cursor);
            Color c = GetColorAt(cursor);
            Color bc = Color.FromArgb(0xff, Color.FromArgb(c.ToArgb() ^ 0xFFFFFF));
            //if (c.ToArgb() != colors[0].ToArgb())
            //{
            //    c = colors[1];
            //}
            lblNuc.ForeColor = bc;
            lblNuc.BackColor = c;
            lblNuc.Text = Hex2nucl((byte)(x)) + Hex2nucl((byte)(y));
        }

        private void chckRuler_CheckStateChanged(object sender, EventArgs e)
        {
            Graphics g = panelSeq.CreateGraphics();
            Color c;
            if (chckRuler.Checked)
            {
                c = Color.Red;
            }
            else
            {
                c = BackColor;
            }
            Brush b = new HatchBrush(HatchStyle.DottedGrid, c, BackColor);
            Pen p = new Pen(b);//(c, 1.0f);
            g.DrawLine(p, 0x80 * schale, 0, 0x80 * schale, 0xFF * schale);
            g.DrawLine(p, 0x70 * schale, 0, 0x70 * schale, 0xFF * schale);
            g.DrawLine(p, 0, 0x80 * schale, 0xFF * schale, 0x80 * schale);
            g.DrawLine(p, 0, 0x70 * schale, 0xFF * schale, 0x70 * schale);

            for (int i = 0; i < 4; i++)
            {
                g.DrawLine(p, (0x20 + i * 0x40) * schale, 0, (0x20 + i * 0x40) * schale, 0xFF * schale);
                g.DrawLine(p, (0x20 + i * 0x40 - 4) * schale, 0, (0x20 + i * 0x40 - 4) * schale, 0xFF * schale);
                g.DrawLine(p, 0, (0x20 + i * 0x40) * schale, 0xFF * schale, (0x20 + i * 0x40) * schale);
                g.DrawLine(p, 0, (0x20 + i * 0x40 - 4) * schale, 0xFF * schale, (0x20 + i * 0x40 - 4) * schale);
            }
        }

        private void cmdCalc_Click(object sender, EventArgs e)
        {
            panelSeq.Refresh();
        }

        private void panelSeq_MouseMove(object sender, MouseEventArgs e)
        {
            ShowNucInfo(e);
        }

        private void SaveSmImage(Panel panel, string fileName)
        {
            int addUpper = 20;

            if (panel == panelSeq)
            {
                using (Bitmap bmp = new Bitmap(panel.Width, panel.Height + addUpper))
                {   //to create bmp of same size as panel plus title
                    Rectangle rect = new Rectangle(0, addUpper, panel.Width, panel.Height); //to set bounds to image
                    panel.DrawToBitmap(bmp, rect);      // drawing panel1 image into bmp of bounds of rect

                    rect = new Rectangle(0, 0, lblPanelSeq.Width, lblPanelSeq.Height);
                    lblPanelSeq.DrawToBitmap(bmp, rect);
                    bmp.Save(fileName, System.Drawing.Imaging.ImageFormat.Png); //save location and type
                }
            }
            else
            {
                Point location = panel.Location;
                location.Y -= addUpper;
                Point pScreen = panel.Parent.PointToScreen(location);
                using (Bitmap bitmap = new Bitmap(panel.Width, panel.Height + addUpper))
                {
                    using (Graphics g = Graphics.FromImage(bitmap))
                    {
                        Size size = panel.Size;
                        size.Height += addUpper;
                        Thread.Sleep(00); // to get rid of extras from the screen
                        g.CopyFromScreen(pScreen, new Point(0, 0), size);
                    }

                    bitmap.Save(fileName, System.Drawing.Imaging.ImageFormat.Png);
                }
            }

            MessageBox.Show(string.Format("Saved to '{0}'", fileName), "SumMatrix", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void panelSeq_Paint(object sender, PaintEventArgs e)
        {
            if (!File.Exists(txtSM.Text))
            {
                return;
            }

            Graphics g = e.Graphics;

            nuc2hex.SumMatrix sm = new nuc2hex.SumMatrix(txtSM.Text, int.Parse(lblLevel.Text));
            for (int y = 0; y < 256; y++)
            {
                for (int x = 0; x < 256; x++)
                {
                    int greys = sm.greys;
                    int a = 255 - sm.NormalizedSumMatrix[x, y] * 255 / (greys-1);
                    Brush brush = GetSmBrush(a);
                    g.FillRectangle(brush, (int)(x * schale), (int)(y * schale), (int)schale, (int)schale);
                }
            }

            //bmpSeq = new Bitmap(panelSeq.Width, panelSeq.Height);//to create bmp of same size as panel
            //Rectangle rect = new Rectangle(0, 0, panelSeq.Width, panelSeq.Height); //to set bounds to image
            //panelSeq.DrawToBitmap(bmpSeq, rect);      // drawing panel1 image into bmp of bounds of rect

            //SumMatrixCalc();
            //double ratio = 255.0 / maxMatrixVal;

            //for(int x=0;x<256;x++)
            //    for(int y=0;y<256;y++)
            //    {
            //        int aVal = (from m in median
            //                   where m >= SumMartrix[x, y]
            //                   select m
            //                        ).FirstOrDefault();

            //        int a = Array.IndexOf(median, aVal);
            //        if (a > 255) a = 255;
            //        a = 255 - a;

            //        //Pen pen = new Pen(Color.FromArgb((int)(SumMartrix[x, y] / maxVal * 255), Color.Blue));
            //        //Brush brush = new SolidBrush(Color.FromArgb((int)(SumMartrix[x, y] * ratio), Color.Blue));
            //        Brush brush = new SolidBrush(Color.FromArgb(0xff, a, a, a));
            //        g.FillRectangle(brush, x * 2, y * 2, 2, 2);
            //    }
        }

        private SolidBrush GetSmBrush(int a)
        {
            return new SolidBrush(
                Color.FromArgb(
                (int)(0xff * BrushMask[0]),
                (int)(a * BrushMask[1]),
                (int)(a * BrushMask[2]),
                (int)(a * BrushMask[3])));
        }

        private void slideColor_ValueChanged(object sender, EventArgs e)
        {
            BrushMask[1] = (slideColor.Value & 0x4) >> 2;
            BrushMask[2] = (slideColor.Value & 0x2) >> 1;
            BrushMask[3] = (slideColor.Value & 0x1);
            slideColor.BackColor = Color.FromArgb(0xff, 0xff * (int)BrushMask[1], 0xff * (int)BrushMask[2], 0xff * (int)BrushMask[3]);
        }

        private void slideColor_MouseUp(object sender, MouseEventArgs e)
        {
            panelSeq.Refresh();
        }

        private void slideColor_KeyUp(object sender, KeyEventArgs e)
        {
            panelSeq.Refresh();
        }

        Panel contextPanel;
        private string ExtPanel1()
        {
            string endPos = "";
            if (contextPanel == panel1)
            {
                endPos = "." + ((pos + bufSize) / 1024).ToString() + "K";
            }
            return endPos;
        }
        private void mnuSaveImage_Click(object sender, EventArgs e)
        {
            string colorExt = "";
            if (contextPanel == panelSeq && slideColor.Value != 7)
            {
                colorExt = "." + slideColor.Value.ToString();
            }
            string fileName = txtSM.Text + colorExt + ExtPanel1() + ".png";
            SaveSmImage(contextPanel, fileName);
        }

        private void saveImageAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string colorExt = "";
            if (contextPanel == panelSeq)
            {
                if (slideColor.Value < slideColor.Maximum)
                {
                    colorExt = "." + slideColor.Value.ToString();
                }
            }
            string level = "";
            if (slideLevel.Value < slideLevel.Maximum)
            {
                level = slideLevel.Value.ToString();
            }
            saveFileDialog1.AddExtension = true;
            saveFileDialog1.DefaultExt = ".png";
            //saveFileDialog1.InitialDirectory = Path.GetDirectoryName(txtSM.Text);
            saveFileDialog1.FileName = Path.GetFileName(txtSM.Text) + level + colorExt + ExtPanel1() + ".png";
            if (saveFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                SaveSmImage(contextPanel, saveFileDialog1.FileName);
            }
        }

        private void slideZoom_Scroll(object sender, EventArgs e)
        {
            schale = slideZoom.Value;
            panelSeq.Height = (int)(256 * schale);
            panelSeq.Width = (int)(256 * schale);
            panelSeq.Refresh();
        }

        private void mnuSaveHex_Click(object sender, EventArgs e)
        {
            int level = int.Parse(lblLevel.Text);
            string fileName = txtSM.Text + level.ToString();

            // write Normalized SumMatrix
            nuc2hex.SumMatrix sm = new SumMatrix(txtSM.Text, level);
            using (FileStream writeSM = new FileStream(fileName, FileMode.Create))
            using (TextWriter textSM = new StreamWriter(writeSM))
            {
                StringBuilder sb = new StringBuilder();
                for (int y = 0; y <= SumMartrix.GetUpperBound(1); y++)
                {
                    for (int x = 0; x <= SumMartrix.GetUpperBound(0); x++)
                    {
                        sb.AppendFormat("{0}\t", sm.NormalizedSumMatrix[x, y]);
                    }
                    string aLine = sb.ToString();
                    aLine = aLine.TrimEnd('\t');
                    textSM.WriteLine(aLine);
                    sb.Clear();
                }
                textSM.Close();
            }

            MessageBox.Show(string.Format("Saved to '{0}'", fileName), "SumMatrix", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void slideLevel_ValueChanged(object sender, EventArgs e)
        {
            lblLevel.Text = slideLevel.Value.ToString();
        }

        private void slideLevel_MouseUp(object sender, MouseEventArgs e)
        {
            panelSeq.Refresh();
        }

        private void slideLevel_KeyUp(object sender, KeyEventArgs e)
        {
            panelSeq.Refresh();
        }

        private void chckRuler_CheckedChanged(object sender, EventArgs e)
        {

        }

        private void panelSeq_MouseDown(object sender, MouseEventArgs e)
        {
            contextPanel = panelSeq;
        }

        private void panel1_MouseDown(object sender, MouseEventArgs e)
        {
            contextPanel = panel1;
        }

        private void txtSource_TextChanged(object sender, EventArgs e)
        {
            txtResultHex.Text = txtSource.Text + "." + transTable + ".n-t.hex";
            txtSM.Text = txtResultHex.Text + ".sm";
        }

        private void chckDraw_CheckedChanged(object sender, EventArgs e)
        {
            if (chckDraw.Checked)
            {
                pForm pf = new pForm(this);
                Thread thr = new Thread(new ThreadStart(pf.DrawFigure));
                thr.Start();
            }
            else
            {
                lblLine.Text = (pos / 1024).ToString() + "K";
            }
        }

        private string DirFileCaption(string fullFileName)
        {
            string fName = Path.GetFileName(fullFileName);
            string dir = Path.GetDirectoryName(fullFileName);
            string[] aDir = dir.Split('\\');
            string caption = string.Format("{0} \\ {1}", aDir[aDir.Length - 1], fName);
            return caption;
        }

        private void txtResult_TextChanged(object sender, EventArgs e)
        {
            lblPanel1.Text = DirFileCaption(txtResultHex.Text);
        }

        private void txtSM_TextChanged(object sender, EventArgs e)
        {
            string level = "";
            if (slideLevel.Value < slideLevel.Maximum)
            {
                level = slideLevel.Value.ToString();
            }

            lblPanelSeq.Text = DirFileCaption(txtSM.Text) + level;
        }

        private void cmdOpenSM_Click(object sender, EventArgs e)
        {
            ShowOpenDialog("SumMatrix Files (*.sm?)|*.sm?", txtSM);
        }

        private void ShowOpenDialog(string fileName, TextBox txtBox)
        {
            OpenFileDialog openFileDialog1 = new OpenFileDialog();
            openFileDialog1.Filter = fileName + "|All Files (*.*)|*.*";
            openFileDialog1.FilterIndex = 1;
            DialogResult res = openFileDialog1.ShowDialog();
            if (res == DialogResult.OK)
            {
                txtBox.Text = openFileDialog1.FileName;
                pos = 0;
                ClearPanel();
            }
        }

        private void cmdCounter_Click(object sender, EventArgs e)
        {
            try
            {
                using (FileStream fs = new FileStream(txtResultHex.Text, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                {
                    lblLine.Text = "";
                    int count = 0, total = 0, cnt = 0;
                    byte[] buf = new byte[bufSize];
                    while ((cnt=fs.Read(buf, 0, bufSize)) > 0)
                    {
                        total += cnt;
                        lblLine.Text = count.ToString();
                        for (int i = 0; i < buf.Count() / 2; i++)
                        {
                            int X = buf[i * 2], Y= buf[i * 2 + 1];
                            //if (
                            //    (X << 8) + Y == 0x7575 || 
                            //    (X << 8) + Y == 0x757D ||
                            //    (X << 8) + Y == 0x757C ||
                            //    (X << 8) + Y == 0x7777 ||
                            //    (X << 8) + Y == 0x7f73 ||
                            //    (X << 8) + Y == 0x7f76 ||
                            //    (X << 8) + Y == 0x7f78 
                            //    )
                            //{
                            //    count++;
                            //}

                            //if ((0x70 < X && X < 0x80) && (0x70 < Y && Y < 0x80))
                            //{
                            //    count++;
                            //}

                            if (0x77 == Y)
                            {
                                count++;
                            }
                        }
                    }
                    fs.Close();
                    lblLine.Text = count.ToString() + " of " + total.ToString();
                }

            }
            catch (Exception ex)
            {
                toolStripStatusLabel1.Text = ex.Message;
            }

        }

        private void cmdDraw16_Click(object sender, EventArgs e)
        {
            DrawFigure16();
        }

        private void fsCmbBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (fsCmbBox.Text != "0")
            {
                string fs = ".fs" + fsCmbBox.Text;
                txtResultHex.Text = txtSource.Text + "." + transTable + fs + ".n-t.hex";
                txtSM.Text = txtResultHex.Text + fs + ".sm";
            }
        }

    }

    public class pForm
    {
        Form1 _form;
        public pForm(Form1 form)
        {
            _form = form;
        }

        public void DrawFigure()
        {
            while (_form._chckDraw.Checked)
            {
                _form.DrawFigure();
                Thread.Sleep(10);
            }
        }
    }


}
